﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Linq;
using Scoreboard.Data;
using Scoreboard.Basement;
using Scoreboard.Model.Authentication;

namespace Scoreboard.Model
{
	public partial class Group
	{
		private const int ScoresDifferencePenaltyPerGame = 3;

		private IEnumerable<Participant> _table;		

		public IEnumerable<Game> GamesByDate
		{
			get { return Games.OrderByDescending(g => g.Date); }
		}

		public IEnumerable<Participant> Table
		{
			get
			{
				if (_table == null)
				{
					FillTable();
				}
				return _table;
			}
			set
			{
				_table = value;
				RaisePropertyChanged("Table");
			}
		}

		public bool KeepsScore
		{
			get
			{
				return AppSettings.KeepsScore;
			}			
		}

		public Group SelfForTemplate
		{
			get { return this; }
		}

		public bool ContainsUser(ScoreboardUser user)
		{
			return Participants.Where(p => p.BelongsTo(user)).Count() == 1;
		}

		public void Refresh()
		{
			Table = null;
			RaisePropertyChanged("SelfForTemplate");
		}

		public IEnumerable<User> GetUsersLeftToPlayWith()
		{
			var currentParticipant = Participants
				.Where(p => p.BelongsTo(WebContext.Current.User))
				.Single();

			var participants = Participants.Except(new[] { currentParticipant });
			foreach (var game in Games)
			{
				if (game.Participant.BelongsTo(WebContext.Current.User))
				{
					participants = participants.Except(new[] { game.Opponent });
				}
			}

			return participants.Select(p => p.Player);
		}

		private void FillTable()
		{
			var table = new List<Participant>(Participants);
			table.ForEach(p => { p.GamesNumber = 0; p.PointsNumber = 0; p.ScoresDifference = 0; } );

			if (Participants.Count > 2)
			{
				foreach (var game in Games)
				{
					var participant = GetEqualParticipant(game.Participant);
					var opponent = GetEqualParticipant(game.Opponent);

					participant.GamesNumber++;
					opponent.GamesNumber++;

					participant.ScoresDifference += game.ParticipantScore - game.OpponentScore;
					opponent.ScoresDifference += game.OpponentScore - game.ParticipantScore;
					
					participant.PointsNumber += GetFirstParticipantPointsNumber(
						game.ParticipantScore, game.OpponentScore);
					opponent.PointsNumber += GetFirstParticipantPointsNumber(
						game.OpponentScore, game.ParticipantScore);
				}

				if (Stage.IsFinished)
				{
					int fullGamesNumberForOnePlayer = Participants.Count - 1;
					table.ForEach(
						p => { p.ScoresDifference -= (fullGamesNumberForOnePlayer - p.GamesNumber)*ScoresDifferencePenaltyPerGame; });
				}

				Table = table.OrderByDescending(p => p.PointsNumber).ThenByDescending(p => p.ScoresDifference).ThenBy(p => p.GamesNumber);

				int j = 1;
				foreach (var participant in Table)
				{
					participant.Place = j;
					j++;
				}
			}
			else if (Games.Count == 1)
			{
				var game = Games.First();

				var participant = table.Where(p => p == game.Participant).Single();
				participant.Score = game.ParticipantScore;

				var opponent = table.Where(p => p == game.Opponent).Single();
				opponent.Score = game.OpponentScore;

				if (participant.Score > opponent.Score)
				{
					participant.IsWinner = true;
					opponent.IsWinner = false;
				}
				else if (participant.Score < opponent.Score)
				{
					participant.IsWinner = false;
					opponent.IsWinner = true;
				}
				else
				{
					participant.IsWinner = false;
					opponent.IsWinner = false;
				}

				Table = table;
			}
			else
			{
				foreach (var participant in table)
				{
					participant.IsWinner = false;
				}

				Table = table;
			}
		}		

		private double GetFirstParticipantPointsNumber(double score1, double score2)
		{
			if (score1 > score2)
			{
				return 1;
			}
			if (score1 < score2)
			{
				return 0;
			}
			return 0.5;
		}

		private Participant GetEqualParticipant(Participant participant)
		{
			return Participants.Where(p => p == participant).Single();
		}
	}
}
